package com.yj.ccs.abs.web.asset.service;

import com.yj.ccs.abs.boot.pagination.Page;
import com.yj.ccs.abs.common.enums.*;
import com.yj.ccs.abs.web.asset.dto.AssetListDto;
import com.yj.ccs.abs.web.asset.dto.UpdateAssetStatusDto;
import com.yj.ccs.abs.web.asset.entity.*;
import com.yj.ccs.abs.web.asset.mapper.*;
import com.yj.ccs.abs.web.common.entity.Attachment;
import com.yj.ccs.abs.web.common.mapper.AttachmentMapper;
import com.yj.ccs.abs.web.management.entity.User;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;

/**
 * Copyright 2018 (C) Yunjian-VC
 * Created on : 2018/3/21
 * Author     : Unbelievable9
 **/
@Service
public class AssetService {

    // TODO: 所有信息需要结算后需处理 money_left 字段

    private final AssetMapper assetMapper;
    private final ContractMapper contractMapper;
    private final PropertyOwnershipMapper propertyOwnershipMapper;
    private final ReceiptMapper receiptMapper;
    private final SettleAccountMapper settleAccountMapper;
    private final FundRestreamMapper fundRestreamMapper;
    private final RemarkMapper remarkMapper;
    private final AssetPageMapper assetPageMapper;
    private final AttachmentMapper attachmentMapper;

    @Autowired
    public AssetService(AssetMapper assetMapper,
                        ContractMapper contractMapper,
                        PropertyOwnershipMapper propertyOwnershipMapper,
                        ReceiptMapper receiptMapper,
                        SettleAccountMapper settleAccountMapper,
                        FundRestreamMapper fundRestreamMapper,
                        RemarkMapper remarkMapper,
                        AssetPageMapper assetPageMapper,
                        AttachmentMapper attachmentMapper) {
        this.assetMapper = assetMapper;
        this.contractMapper = contractMapper;
        this.propertyOwnershipMapper = propertyOwnershipMapper;
        this.receiptMapper = receiptMapper;
        this.settleAccountMapper = settleAccountMapper;
        this.fundRestreamMapper = fundRestreamMapper;
        this.remarkMapper = remarkMapper;
        this.assetPageMapper = assetPageMapper;
        this.attachmentMapper = attachmentMapper;
    }

    public Asset getAssetById(Long id) {
        return assetMapper.getById(id);
    }

    public Page<AssetPageInfo> getAssetPage(AssetListDto assetListDto) {
        Page<AssetPageInfo> page = assetPageMapper.getMiniAssetOnCondition(assetListDto);
        List<AssetPageInfo> pageInfoList = page.getPageResult();

        // 计算余额
        for (AssetPageInfo assetPageInfo : pageInfoList) {
            BigDecimal moneyPaid = fundRestreamMapper.countSumMoneyForAssetId(assetPageInfo.getId());

            if (moneyPaid == null) {
                moneyPaid = BigDecimal.ZERO;
            }

            assetPageInfo.setMoney_left(assetPageInfo.getMoney_sum().subtract(moneyPaid).setScale(2, RoundingMode.HALF_UP));
        }

        return page;
    }

    @Transactional
    public String updateAssetStatus(UpdateAssetStatusDto updateAssetStatusDto, User user) {
        String errorMessage = null;
        Boolean legalStatus = true;

        List<Asset> assetList = assetMapper.getByIds(updateAssetStatusDto.getAsset_id_list());

        if (assetList == null || assetList.size() != updateAssetStatusDto.getAsset_id_list().size()) {
            errorMessage = "资产ID中存在无效数据";

            return errorMessage;
        }

        if (user.getRole_type().equals(UserRoleType.ORIGINATOR)) {
            if (updateAssetStatusDto.getAssetStatusType().equals(AssetStatusType.WAIT_TO_APPLY)) {
                errorMessage = "原始权益人无法退回资产";
                legalStatus = false;
            } else if (updateAssetStatusDto.getAssetStatusType().equals(AssetStatusType.WAIT_TO_REDEEM)) {
                errorMessage = "原始权益人无法赎回资产";
                legalStatus = false;
            }
        } else if (user.getRole_type().equals(UserRoleType.PLAN_ADMIN)) {
            if (updateAssetStatusDto.getAssetStatusType().equals(AssetStatusType.WAIT_TO_VERIFY)) {
                errorMessage = "计划管理人无法提交资产入池进行审核";
                legalStatus = false;
            } else if (updateAssetStatusDto.getAssetStatusType().equals(AssetStatusType.WAIT_TO_BUY_BACK)) {
                errorMessage = "计划管理人无法回购资产";
                legalStatus = false;
            }
        }

        if (legalStatus) {
            assetMapper.batchUpdateStatus(updateAssetStatusDto.getAsset_id_list(), updateAssetStatusDto.getAssetStatusType().getValue());

            if (updateAssetStatusDto.getAssetStatusType().equals(AssetStatusType.IN_POOL)) {
                assetMapper.batchUpdatePoolDate(LocalDate.now(), updateAssetStatusDto.getAsset_id_list());
            } else if (updateAssetStatusDto.getAssetStatusType().equals(AssetStatusType.RECOVERED)) {
                assetMapper.batchUpdateRecyclelDate(LocalDate.now(), updateAssetStatusDto.getAsset_id_list());

                // 确认回购（赎回）自动生成回款记录
                List<FundRestream> fundRestreamList = new ArrayList<>();

                for (Asset asset : assetList) {
                    FundRestream fundRestream = new FundRestream();
                    fundRestream.setAsset_id(asset.getId());
                    fundRestream.setDate(LocalDate.now());
                    fundRestream.setMoney(asset.getAvailable_money());

                    if (asset.getStatus().equals(AssetStatusType.WAIT_TO_BUY_BACK)) {
                        fundRestream.setSource(FundRestreamSourceType.CREDITOR_BUY_BACK);
                    } else if (asset.getStatus().equals(AssetStatusType.WAIT_TO_REDEEM)) {
                        fundRestream.setSource(FundRestreamSourceType.CREDITOR_REDEEM);
                    }

                    fundRestreamList.add(fundRestream);

                    assetMapper.updateAvailableMoneyById(BigDecimal.ZERO, asset.getId());
                }

                if (fundRestreamList.size() > 0) {
                    fundRestreamMapper.batchInsert(fundRestreamList);
                }
            }
        }

        return errorMessage;
    }

    public AssetTopInfo getAssetTopInfo(Asset asset) {
        Contract downstreamContract = contractMapper.getByAssetIdAndType(asset.getId(), ContractType.DOWNSTREAM.getValue());

        if (downstreamContract == null) {
            return null;
        } else {
            AssetTopInfo assetTopInfo = new AssetTopInfo();
            BeanUtils.copyProperties(asset, assetTopInfo);
            assetTopInfo.setDebtor(downstreamContract.getBuyer());
            assetTopInfo.setCreditor(downstreamContract.getSeller());
            assetTopInfo.setStatus(asset.getStatus());

            BigDecimal fundRestreamMoneyPaid = fundRestreamMapper.countSumMoneyForAssetId(asset.getId());

            if (fundRestreamMoneyPaid != null && fundRestreamMoneyPaid.compareTo(BigDecimal.ZERO) > 0) {
                fundRestreamMoneyPaid = fundRestreamMoneyPaid.setScale(2, RoundingMode.HALF_UP);
                assetTopInfo.setMoney_repaid(fundRestreamMoneyPaid);
            }

            assetTopInfo.setMoney_left(assetTopInfo.getMoney_sum().subtract(assetTopInfo.getMoney_repaid()).setScale(2, RoundingMode.HALF_UP));
            assetTopInfo.setUse_days(ChronoUnit.DAYS.between(asset.getStart_date(), LocalDate.now()));
            assetTopInfo.setExpire_days(ChronoUnit.DAYS.between(asset.getPredict_date(), LocalDate.now()));

            BigDecimal settleAccountTotalPrice = settleAccountMapper.getTotalPriceByAssetId(asset.getId());

            if (settleAccountTotalPrice != null && settleAccountTotalPrice.compareTo(BigDecimal.ZERO) > 0) {
                settleAccountTotalPrice = settleAccountTotalPrice.setScale(2, RoundingMode.HALF_UP);
                assetTopInfo.setSettled_price(settleAccountTotalPrice);
            }

            BigDecimal settleAccountTotalAmount = settleAccountMapper.getTotalAmountByAssetId(asset.getId());

            if (settleAccountTotalAmount != null && settleAccountTotalAmount.compareTo(BigDecimal.ZERO) > 0) {
                settleAccountTotalAmount = settleAccountTotalAmount.setScale(2, RoundingMode.HALF_UP);
                assetTopInfo.setSettled_amount(settleAccountTotalAmount);
            }

            if (asset.getMoney_sum() != null && asset.getMoney_sum().compareTo(BigDecimal.ZERO) > 0) {
                BigDecimal settled_rate = assetTopInfo.getSettled_price().divide(asset.getMoney_sum(), 4, RoundingMode.HALF_UP);
                settled_rate = settled_rate.multiply(BigDecimal.valueOf(100));

                assetTopInfo.setSettled_rate(settled_rate);
            }

            return assetTopInfo;
        }
    }

    public AssetBasicInfo getAssetBasicInfo(Asset asset) {
        AssetBasicInfo assetBasicInfo = new AssetBasicInfo();
        BeanUtils.copyProperties(asset, assetBasicInfo);
        assetBasicInfo.setLevel(AssetLevelType.fromValue(asset.getLevel().getValue()));
        assetBasicInfo.setExpire_days(ChronoUnit.DAYS.between(asset.getPredict_date(), LocalDate.now()));
        assetBasicInfo.setGuarantee(AssetGuaranteeType.fromValue(asset.getGuarantee().getValue()));

        BigDecimal moneyPaid = fundRestreamMapper.countSumMoneyForAssetId(asset.getId());

        if (moneyPaid != null && moneyPaid.compareTo(BigDecimal.ZERO) > 0) {
            assetBasicInfo.setMoney_left(assetBasicInfo.getMoney_sum().subtract(moneyPaid).setScale(2, RoundingMode.HALF_UP));
        }

        BigDecimal moneyBalanced = settleAccountMapper.getTotalPriceByAssetId(asset.getId());

        if (moneyBalanced != null && moneyBalanced.compareTo(BigDecimal.ZERO) > 0) {
            assetBasicInfo.setBalanced(true);
            assetBasicInfo.setMoney_balanced(moneyBalanced);
        }

        // 保险单附件
        if (assetBasicInfo.getInsured()) {
            List<Attachment> insurance_files = attachmentMapper.getByIdAndType(asset.getId(), AttachmentType.BASIC_INSURED.getValue());
            assetBasicInfo.setInsurance_files(insurance_files);
        }

        // 担保文件附件
        if (!assetBasicInfo.getGuarantee().equals(AssetGuaranteeType.NONE)) {
            List<Attachment> guarantee_files = attachmentMapper.getByIdAndType(asset.getId(), AttachmentType.BASIC_GUARANTEE.getValue());
            assetBasicInfo.setGuarantee_files(guarantee_files);
        }

        // 质保文件附件
        if (assetBasicInfo.getDeposited()) {
            List<Attachment> deposited_files = attachmentMapper.getByIdAndType(asset.getId(), AttachmentType.BASIC_DEPOSITED.getValue());
            assetBasicInfo.setDeposited_files(deposited_files);
        }

        // 展期条款文件附件
        if (assetBasicInfo.getExpanded()) {
            List<Attachment> expanded_files = attachmentMapper.getByIdAndType(asset.getId(), AttachmentType.BASIC_EXPANDED.getValue());
            assetBasicInfo.setExpanded_files(expanded_files);
        }

        return assetBasicInfo;
    }

    public ContractDetail getContractDetailByAssetIdAndType(Long assetId, ContractType contractType) {
        Contract contract = contractMapper.getByAssetIdAndType(assetId, contractType.getValue());

        if (contract == null) {
            return null;
        } else {
            ContractDetail contractDetail = new ContractDetail();
            BeanUtils.copyProperties(contract, contractDetail);
            contractDetail.setTransport_type(ContractTransportType.fromValue(contract.getTransport_type().getValue()));
            contractDetail.setTotal_price(contract.getUnit_price().multiply(contract.getAmount()));
            contractDetail.setType((contractType));

            // 合同影印件附件
            List<Attachment> files = attachmentMapper.getByIdAndType(contract.getId(), AttachmentType.CONTRACT_FILE.getValue());
            contractDetail.setFiles(files);

            // 委托运输协议附件
            if (contractDetail.getConsigned()) {
                List<Attachment> consigned_files = attachmentMapper.getByIdAndType(contract.getId(), AttachmentType.CONTRACT_CONSIGNED.getValue());
                contractDetail.setConsigned_files(consigned_files);
            }

            // 委托收货协议附件
            if (contractDetail.getDelivered()) {
                List<Attachment> delivered_files = attachmentMapper.getByIdAndType(contract.getId(), AttachmentType.CONTRACT_DELIVERED.getValue());
                contractDetail.setDelivered_files(delivered_files);
            }

            // 委托结算协议
            if (contractDetail.getReckoned()) {
                List<Attachment> reckoned_files = attachmentMapper.getByIdAndType(contract.getId(), AttachmentType.CONTRACT_RECKONED.getValue());
                contractDetail.setReckoned_files(reckoned_files);
            }

            return contractDetail;
        }
    }

    public PropertyOwnershipDetail getPropertyOwnershipDetail(Long assetId) {
        PropertyOwnership propertyOwnership = propertyOwnershipMapper.getByAssetId(assetId);

        if (propertyOwnership == null) {
            return null;
        } else {
            PropertyOwnershipDetail propertyOwnershipDetail = new PropertyOwnershipDetail();
            BeanUtils.copyProperties(propertyOwnership, propertyOwnershipDetail);
            propertyOwnershipDetail.setTotal_price(propertyOwnership.getUnit_price().multiply(propertyOwnership.getAmount()).setScale(2, RoundingMode.HALF_UP));

            // 货物照片附件
            List<Attachment> property_files = attachmentMapper.getByIdAndType(propertyOwnership.getId(), AttachmentType.PO_PROPERTY.getValue());
            propertyOwnershipDetail.setProperty_files(property_files);

            // 运输工具照片附件
            List<Attachment> tool_files = attachmentMapper.getByIdAndType(propertyOwnership.getId(), AttachmentType.PO_TOOL.getValue());
            propertyOwnershipDetail.setTool_files(tool_files);

            // 运输照片
            List<Attachment> transport_files = attachmentMapper.getByIdAndType(propertyOwnership.getId(), AttachmentType.PO_TRANSPORT.getValue());
            propertyOwnershipDetail.setTransport_files(transport_files);

            // 过衡单
            List<Attachment> sheet_files = attachmentMapper.getByIdAndType(propertyOwnership.getId(), AttachmentType.PO_SHEET.getValue());
            propertyOwnershipDetail.setSheet_files(sheet_files);

            // 化验单
            List<Attachment> laboratory_files = attachmentMapper.getByIdAndType(propertyOwnership.getId(), AttachmentType.PO_LABORATORY.getValue());
            propertyOwnershipDetail.setLaboratory_files(laboratory_files);

            // 货权转移证明
            List<Attachment> cert_files = attachmentMapper.getByIdAndType(propertyOwnership.getId(), AttachmentType.PO_CERT.getValue());
            propertyOwnershipDetail.setCert_files(cert_files);


            return propertyOwnershipDetail;
        }
    }

    public ReceiptListInfo getReceiptListInfo(Long assetId) {
        ReceiptListInfo receiptListInfo = new ReceiptListInfo();
        receiptListInfo.setItem_list(receiptMapper.getListItemByAssetId(assetId));
        receiptListInfo.setTotal_amount(receiptMapper.getTotalAmountByAssetId(assetId));
        receiptListInfo.setTotal_money(receiptMapper.getTotalMoneyByAssetId(assetId));

        return receiptListInfo;
    }

    public SettleAccountListInfo getSettleAccountListInfo(Long assetId) {
        SettleAccountListInfo settleAccountListInfo = new SettleAccountListInfo();

        List<SettleAccountListItem> list = settleAccountMapper.getListItemByAssetId(assetId);

        if (list != null && list.size() > 0) {
            for (SettleAccountListItem settleAccountListItem : list) {
                settleAccountListItem.setTotal_price(settleAccountListItem.getUnit_price().multiply(settleAccountListItem.getAmount()).setScale(2, RoundingMode.HALF_UP));
            }

            settleAccountListInfo.setItem_list(list);
            settleAccountListInfo.setTotal_amount(settleAccountMapper.getTotalAmountByAssetId(assetId));
            settleAccountListInfo.setTotal_price(settleAccountMapper.getTotalPriceByAssetId(assetId));
            settleAccountListInfo.setWeighted_unit_price(settleAccountListInfo.getTotal_price().divide(settleAccountListInfo.getTotal_amount(), 2, RoundingMode.HALF_UP));
        }

        return settleAccountListInfo;
    }

    public FundRestreamListInfo getFundRestreamListInfo(Long assetId) {
        FundRestreamListInfo fundRestreamListInfo = new FundRestreamListInfo();

        List<FundRestreamListItem> list = fundRestreamMapper.getListItemByAssetId(assetId);

        if (list != null && list.size() > 0) {
            for (FundRestreamListItem fundRestreamListItem : list) {
                BigDecimal rate = fundRestreamListItem.getNote_money().divide(fundRestreamListItem.getMoney(), 4, RoundingMode.HALF_UP);
                rate = rate.multiply(BigDecimal.valueOf(100));

                fundRestreamListItem.setNote_money_rate(rate.setScale(2, RoundingMode.HALF_UP));
            }

            fundRestreamListInfo.setItem_list(list);
            fundRestreamListInfo.setTotal_money(fundRestreamMapper.countSumMoneyForAssetId(assetId));
            fundRestreamListInfo.setTotal_note_money(fundRestreamMapper.countSumNoteMoneyForAssetId(assetId));

            BigDecimal rate = fundRestreamListInfo.getTotal_note_money().divide(fundRestreamListInfo.getTotal_money(), 4, RoundingMode.HALF_UP);
            rate = rate.multiply(BigDecimal.valueOf(100));

            fundRestreamListInfo.setNote_money_rate(rate.setScale(2, RoundingMode.HALF_UP));
        }

        return fundRestreamListInfo;
    }

    public RemarkListInfo getRemarkListInfo(Long assetId) {
        RemarkListInfo remarkListInfo = new RemarkListInfo();
        remarkListInfo.setItem_list(remarkMapper.getListItemByAssetId(assetId));
        remarkListInfo.setTotal_money(remarkMapper.getTotalMoneyByAssetId(assetId));

        return remarkListInfo;
    }
}
